package com.gitee.qdbp.base.shiro.filter;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.util.Assert;

/**
 * JSON消息转换类
 *
 * <pre>
 * &lt;bean id="jsonHttpMessageConverter" class="{pkg}.JsonHttpMessageConverter"&gt;
 *     &lt;property name="messageConverter" ref="fastJsonHttpMessageConverter" /&gt;
 *     &lt;property name="jsonContentType"&gt;
 *         &lt;value&gt;application/json;charset=UTF-8&lt;/value&gt;
 *     &lt;/property&gt;
 *     &lt;property name="jsonSuffixes"&gt;
 *         &lt;list&gt; &lt;value&gt;.json&lt;/value&gt; &lt;/list&gt;
 *     &lt;/property&gt;
 *     &lt;property name="jsonHeaders"&gt;
 *         &lt;list&gt; &lt;value&gt;XMLHttpRequest&lt;/value&gt; &lt;/list&gt;
 *     &lt;/property&gt;
 *     &lt;property name="jsonHeaderName"&gt;
 *         &lt;value&gt;X-Requested-With&lt;/value&gt;
 *     &lt;/property&gt;
 * &lt;/bean&gt;
 * </pre>
 *
 * @author zhaohuihua
 * @version 150919
 */
public class JsonHttpMessageConverter<T> {

    private HttpMessageConverter<Object> messageConverter;

    private MediaType jsonContentType = new MediaType("application", "json", Charset.forName("UTF-8"));

    private List<String> jsonSuffixes = Arrays.asList(".json");

    private List<String> jsonHeaders = Arrays.asList("XMLHttpRequest");

    private String jsonHeaderName = "X-Requested-With";

    public void write(T message, HttpServletResponse resp) throws IOException {
        Assert.notNull(messageConverter, "HttpMessageConverter must not be null");

        // 如果是以JSON结尾, 或含有JSON的头信息, 按JSON格式输出"用户未登录"
        ServletServerHttpResponse ssresp = new ServletServerHttpResponse(resp);
        try {
            messageConverter.write(message, jsonContentType, ssresp);
        } catch (HttpMessageNotWritableException e) {
            String s = "HttpMessageConverter not writable for " + jsonContentType;
            throw new IllegalStateException(s, e);
        }
    }

    public boolean isJsonRequest(HttpServletRequest request) {
        return isJsonSuffix(request) || hasJsonHeaders(request);
    }

    private boolean isJsonSuffix(HttpServletRequest request) {
        if (jsonSuffixes == null || jsonSuffixes.isEmpty()) {
            return false;
        }
        String uri = request.getRequestURI();
        for (String suffix : jsonSuffixes) {
            if (uri.endsWith(suffix)) {
                return true;
            }
        }
        return false;
    }

    private boolean hasJsonHeaders(HttpServletRequest request) {
        String with = request.getHeader(jsonHeaderName);
        if (with == null || jsonHeaders == null || jsonHeaders.isEmpty()) {
            return false;
        }

        for (String string : jsonHeaders) {
            if (with.equalsIgnoreCase(string)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 设置messageConverter
     *
     * @param messageConverter messageConverter
     */
    public void setMessageConverter(HttpMessageConverter<Object> messageConverter) {
        this.messageConverter = messageConverter;
    }

    /**
     * 设置contentType
     *
     * @param contentType contentType
     */
    public void setJsonContentType(MediaType jsonContentType) {
        this.jsonContentType = jsonContentType;
    }

    /**
     * 设置jsonSuffixes
     *
     * @param jsonSuffixes jsonSuffixes
     */
    public void setJsonSuffixes(List<String> jsonSuffixes) {
        this.jsonSuffixes = jsonSuffixes;
    }

    /**
     * 设置jsonHeaders
     *
     * @param jsonHeaders jsonHeaders
     */
    public void setJsonHeaders(List<String> jsonHeaders) {
        this.jsonHeaders = jsonHeaders;
    }

    /**
     * 设置jsonHeaderName
     *
     * @param jsonHeaderName jsonHeaderName
     */
    public void setJsonHeaderName(String jsonHeaderName) {
        this.jsonHeaderName = jsonHeaderName;
    }
}
